#include "Server.h"

using namespace std;

bool is_move(string move) {
	if(move.length() != 2) {
		return false;
	}
	char x_pos = move[0];
	char y_pos = move[1];

	if( x_pos == '0' || y_pos == '0' ){
		return false;
	}

	if( isxdigit(x_pos) && isxdigit(y_pos) ) {
		return true;
	} else {
		return false;
	}

}

//Parse
int to_hex(char character) {	
	int c = (int) character;
	if( 49 <= c && c <= 57 ) {
		c = c - 48; //for 1-9
	} 
	if(65 <= c && c <= 70) {
		c = c - 55; //for capital letters
	}
	if(97 <= c && c <= 102) {
		c = c - 87; //for lowercase letters
	}

	return c;
}

//Parse
vector<string> tokenize(char* buf) {
	vector<string> return_vec;
	string word = "";

	for(size_t i=0; i<strlen(buf); i++){
		if(isspace(buf[i])) {
			if(word.length() > 0) {
				return_vec.push_back(word);
				//cout<<"Word	:	"<<word<<endl;
				word = "";
			}
		} else {
			word = word+buf[i];
		}

	}
	if(word != "") {
		return_vec.push_back(word);
		//cout<<"Word	:	"<<word<<endl;
	}
	return return_vec;
}

void Server::toggle_display() {
	display = !display;
}

void Server::set_difficulty(string val){

	cout<<"Server::set_difficulty"<<endl;
	if(val == "EASY"){
		al.set_difficulty(EASY);
	} else if(val == "MEDIUM"){
		al.set_difficulty(MEDIUM);
	} else if(val == "HARD"){
		al.set_difficulty(HARD);
	} else {
		//this should never happen
		cout<<"ERROR: Set diffiulty, given"<<val<<endl;
	}
}

void Server::send_ack(ACK a) {
	string message = "";
	switch (a)
	{
		case WELCOME:
			message = "WELCOME";
			break;
		case OK:
			message = "OK";
			break;
		case MOVE:
			message = game.last_move();
			break;
		case comment:
			message = "I dont know what goes here";
			break;
		case whitewin:
			message = "***WHITE_WINS***";
			break;
		case blackwin:
			message = "***BLACK_WINS***";
			break;
		default:
			message = "ILLEGAL";
	}



	message+="\n";

	if(game_play == AI_AI)
	{
		if(display)
		{
			string board_string = game.display();
			write(sockfd,board_string.c_str(),board_string.length());
		}

		cout<<"Sending: "<<message<<";\n";
		write(server_sockfd,message.c_str(),message.length());
		return;
	}
	
	if(display) {

		string board_string = game.display();
		message += board_string;
	}
	cout<<"Writing: "<<message;
	write(sockfd,message.c_str(),message.length());
};

//Server
int Server::make_move(string move) {

	int x_pos = to_hex(move[0]);
	int y_pos =  to_hex(move[1]);

	
	game.move(x_pos, y_pos, BLACK);
	cout<<"Game move sucess"<<endl;
	if(game.check_state() == 1)
	{
		send_ack(blackwin);
		cout<<"Make move : 1\n";
		return 1;
	}
	//Al handles the server move
	al.move();
	//server_move = game.last_move();
	//cout<<"Server_move = "<<server_movefai<<endl;
	
	if(game.check_state() == 1)
	{
		send_ack(whitewin);
		cout<<"Make move : 1\n";
		return 1;
	}
	return 0;
}

//Server
bool Server::validate_move(string move) {
	int x_pos = to_hex(move[0]);
	int y_pos =  to_hex(move[1]);

	return game.validate_move(x_pos, y_pos);
}




//Parse
bool Server::parse(vector<string> message) {

	for(size_t i=0; i< message.size(); i++) {
		cout<<"Server::parse mesage = "<<message[i]<<";"<<endl;

		if(message[i] == "EXIT") {
			///shutdown should return a value
			send_ack(OK);
			this->shutdown(sockfd);
			this->shutdown(server_sockfd);
		} else if(message[i] == "DISPLAY") {
			toggle_display();
			send_ack(OK);
		} else if(message[i] == "EASY" || message[i] == "MEDIUM" || message[i] == "HARD"){
			set_difficulty(message[i]);
			send_ack(OK);
		} else if(message[i] == "UNDO") {
			game.undo();
			send_ack(OK);
		} else if(message[i] == "HUMAN-AI") {
			//TODO: human vs AI mode
			if(game_play == HUMAN_AI)
				this->shutdown(server_sockfd);
			game_play = HUMAN_AI;
			send_ack(OK);
		} else if(message[i] == "AI-AI") {
			if(message.size() >= 3){
				game_play = AI_AI;
				message.erase (message.begin()+i);
				
				server_addr = message[i];
				message.erase (message.begin()+i);
				
				server_port = atoi(message[i].c_str());
				message.erase (message.begin()+i);
			}
			send_ack(OK);
			al.toggle_piece();
			this->connect_server();
				
		} else if(is_move(message[i])){
			if(!validate_move(message[i])) {
				cout<<"Sendin illegal"<<endl;
				send_ack(ILLEGAL);
			} else {
				//if the game is not over
				if(	make_move(message[i]) == 0) {
					send_ack(MOVE);	
				} else {
					shutdown(sockfd);
					shutdown(server_sockfd); 
				}
			}			
		} else {
			send_ack(ILLEGAL);
		}
	}
	return true;
}

void Server::run(){

	char buffer[BUFFER_SIZE];
	int n = 0;

	send_ack(WELCOME);
	 
	char close_str[6] = "Close";

	while(true){
		 bzero(buffer,256);
		 
		if(game_play == HUMAN_AI)
		{
			n = read(sockfd,buffer,255);
		}
		else
		{
			n = read(sockfd,buffer,255);
			n = read(server_sockfd, buffer, 255);
		}
			
		
		 if (n < 0)
		 {
			 perror("ERROR reading from socket");
			 exit(1);
		 }

		
		if(strncmp(buffer,close_str,5) == 0) {
			printf("Close message received. Closing connection\n");
			break;
		}
		
		vector<string> read_message = tokenize(buffer);
		if(game_play == HUMAN_AI)
			printf("Message from sockfd(%d): %s\n",sockfd,buffer);
		else
			printf("Message from sockfd(%d): %s\n",server_sockfd,buffer);
		
		
		parse(read_message);
	}
    this->shutdown(sockfd);
	this->shutdown(server_sockfd);
}

void Server::shutdown(int sock){
	close(sock);
}

void Server::connect_server()
{
	struct hostent *server;
	struct sockaddr_in serv_addr;
	
    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
	
    if (sockfd < 0) 
        perror("ERROR opening socket");
		
    server = gethostbyname(server_addr.c_str());
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }
	
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
	
        bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
		 
    serv_addr.sin_port = htons(server_port);
	
    if (connect(server_sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        perror("ERROR connecting");

    al.toggle_piece();
	al.move();
	string message = game.last_move();
	cout<<"Al's move"<<message<<endl;
			
	write(server_sockfd,message.c_str(),message.length());
	cout<<"Sending: "<<message<<";\n";
}
